//web后端框架 寄
//支持功能:
//		上下文
//		路由树
//		路由分组 todo 注意分组后路由所在的树
//		解决文件结构导致type的问题以及语言编译/运行时报不能循环import的错误[未解决]
//		中间件 todo 对于分好组的路由中间件处理 :存于组 跑在上下文
//		模板引擎 todo 解析请求的地址，映射到服务器上文件的真实地址 用于获取文件 ; 后端服务器页面 用于爬虫捉取
//		错误处理 todo 中间件的补充

package ji

import (
	"net/http"
	"strings"
)

type H map[string]interface{}

type Engine struct {
	*Router
	groups            []*RouterGroup //groups[0]放没有分组的 groups[1:]放其他组的？
	commonMiddlewares []HandlerFunc  //公共中间件
	templates                        //全局模板文件
}

func (e *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	//从路由组中拿出中间件 然后放到Context中， 启动Router.Handle(Context)
	var middlewares []HandlerFunc
	/*
		for _, group := range e.groups {
			if strings.HasPrefix(r.URL.Path, group.prefix) { // todo 已解决 进不去？ group.prefix 如果是 "api/v1" 当场false
				middlewares = append(middlewares, group.middlewares...)

			}
		}
	*/
	middlewares = append(middlewares, e.commonMiddlewares...)
	for _, group := range e.groups { // 中间件收集者
		if strings.HasPrefix(r.URL.Path, group.prefix) {
			middlewares = append(middlewares, group.middlewares...)
		}
	}
	ctx := newContext(w, r)
	ctx.middlewares = append(ctx.middlewares, middlewares...)
	ctx.templates = e.templates
	e.Router.Handle(ctx)
}

//分割线*****************************************************************

func New() *Engine {
	engine := &Engine{
		Router: newRouter(),
	}
	engine.groups = make([]*RouterGroup, 0)
	engine.commonMiddlewares = make([]HandlerFunc, 0)
	return engine
}

func Default() *Engine {
	engine := New()
	engine.Use(Logger(), Recovery())
	return engine
}
func (e *Engine) Group(prefix string) *RouterGroup {
	newGroup := newRouterGroup(prefix, nil, nil, e.Router)
	e.groups = append(e.groups, newGroup)
	return newGroup
}

func (e *Engine) Use(middlewares ...HandlerFunc) {
	e.commonMiddlewares = append(e.commonMiddlewares, middlewares...)
}

func (e *Engine) GET(path string, handlerFunc HandlerFunc) {
	e.Router.AddRoute("GET", path, handlerFunc)
	//log.Printf("Router: GET ------ %s\n", path)
}

func (e *Engine) POST(path string, handlerFunc HandlerFunc) {
	e.Router.AddRoute("POST", path, handlerFunc)
	//log.Printf("Router: POST ------ %s\n", path)
}

func (e *Engine) Run(addr string) {
	http.ListenAndServe(addr, e)
}
